﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;

namespace DARE
{
    /// <summary>
    /// This is a simple progress bar.
    /// The progress textre can be set and you can play an animation on it.
    /// To change the progression value, just use the Progress property.
    /// </summary>
    [AttrTypeDependentSerializable(typeof(CProgressBarData))]
    public class CProgressBar : CWidget
    {
        #region fields

        private CHudTexture m_barTexture;
        private Rectangle m_barRectangle;
        private float m_progressPercentage;
        private bool m_updated;
        private Color m_barColor;

        private bool m_displayText;
        private string m_percentage;
        private SpriteFont m_spriteFont;
        private Vector2 m_stringPos;
        private Color m_textColor;

        private bool m_stretchBar;
        private Rectangle m_subrect;

        #endregion

        #region properties

        public bool Vertical { get; set; }

        /// <summary>
        /// Gets/Sets the progress bar texture
        /// </summary>
        /// <summary>
        /// Gets/Sets the progress bar texture
        /// </summary>
        public CHudTexture BarTexture { get { return m_barTexture; } set { m_barTexture = value; } }
        
        /// <summary>
        /// set this to false if you want the BarTexture to be dislpayed progressively, else the BarTexture will be stretched.
        /// </summary>
        public bool StretchBar { get { return m_stretchBar; } set { m_stretchBar = value; } }

        /// <summary>
        ///  gets the progress m_percentage with a value between 0 and 100
        ///  sets the progress m_percentage with a value between 0 and 100
        /// </summary>
        public float Progress { get { return m_progressPercentage; } 
            set { m_progressPercentage = value; m_updated = true; } }

        /// <summary>
        /// Gets/Sets the color of the bar
        /// </summary>
        public Color BarColor { get { return m_barColor; } set { m_barColor = value; } }

        /// <summary>
        /// Gets/Sets the color of the text on the bar
        /// </summary>
        public Color TextColor { get { return m_textColor; } set { m_textColor = value; } }

        /// <summary>
        /// If the value is between 0 and 1, the position is a percentage of the size of the parent
        /// (if the parent is null, the value is a percentage of the window).
        /// The value is relative to its parent.
        /// </summary>
        public override Vector2 Position
        {
            get
            {
                return base.Position;
            }
            set
            {
                base.Position = value;
                //updateBarSize();
                m_updated = true;
            }
        }

        /// <summary>
        /// If the value is between 0 and 1, the size is a percentage of the size of the parent
        /// (if the parent is null, the value is a percentage of the window).
        /// Else, the value is absolute.
        /// </summary>
        public override Vector2 Size
        {
            get
            {
                return base.Size;
            }
            set
            {
                base.Size = value;
                //updateBarSize();
                m_updated = true;
            }
        }

        /// <summary>
        /// Gets/Sets the rectangle where the widget will be draw.
        /// This value is automatically set when the position and/or the size are set.
        /// If you plan to use a different rectangle than the one automatically created,
        /// we recommand you to use the UseDrawableRect and DrawableRect properties.
        /// </summary>
        /// <seealso cref="UseDrawableRect"/>
        /// <seealso cref="DrawableRect"/>
        public override Rectangle Rect
        {
            get
            {
                return base.Rect;
            }
            set
            {
                base.Rect = value;
                //updateBarSize();
                m_updated = true;
            }
        }

        /// <summary>
        /// Set this value to true if you want to see the percentage displayed on the progress bar
        /// </summary>
        public bool DisplayText { get { return m_displayText; } set { m_displayText = value; m_updated = true; } }

        #endregion

        #region Actualize

        /// <summary>
        /// Actualizes the widget.
        /// If anything has changed, it will allow this widget to get back its parameters.
        /// For example, if the size of the widget is a percentage of the size of its parent,
        /// if the parent's size changes, it will recalculate the good size of this widget.
        /// (This method is called automatically but you can force a new actualization).
        /// </summary>
        public override void Actualize()
        {
            base.Actualize();
            updateBarSize();
        }

        #endregion

        #region ctor

        public CProgressBar(CHUDSystem hud, CWidget parent, string name)
            : base(hud, parent, name)
        {
            Vertical = false;
            m_stretchBar = true;
            m_subrect = new Rectangle();
            m_updated = false;
            m_progressPercentage = 0;
            m_texture = HUD.Skinner.GetTexture("progressbarbackground");
            m_barTexture = new CHudTexture();
            m_barTexture.Body = new Texture2D(Game.GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
            m_barColor = new Color(50, 205, 50, 175);
            Color[] c = new Color[1]
            {
                m_barColor
            };
            m_barTexture.Body.SetData(c);
            m_barRectangle = new Rectangle(m_rect.X + 5, m_rect.Y + 5, 0, m_rect.Height - 10);
            m_displayText = false;
            m_spriteFont = HUD.Skinner.GetSpriteFont("progressbardefault");
            m_textColor = new Color(50, 205, 50, 255);
            m_margins.Left = 10;
            m_margins.Right = 15;
            m_margins.Top = 3;
            m_margins.Bottom = 3;

            Size = new Vector2(400, 20);
        }

        #endregion

        #region update/draw

        private void updateBarSize()
        {
            m_percentage = string.Format("{0:0.0} %", m_progressPercentage);
            m_stringPos = new Vector2(m_rect.X + ((m_rect.Width / 2.0f) - (m_spriteFont.MeasureString(m_percentage).X / 2.0f)), m_rect.Y);
            if (m_progressPercentage == 0)
            {
                if (Vertical)
                    m_barRectangle.Height = 0;
                else
                    m_barRectangle.Width = 0;
                return;
            }
            if (Vertical)
            {
                m_barRectangle.Height = (int)(m_progressPercentage * (m_rect.Height - (m_margins.Top + m_margins.Bottom)) / 100.0f);
                m_barRectangle.X = (int)(m_rect.X + m_margins.Left);
                m_barRectangle.Y = (int)(m_rect.Y + m_rect.Height - m_margins.Bottom - m_barRectangle.Height);
                m_barRectangle.Width = (int)(m_rect.Width - m_margins.Right - m_margins.Left);
            }
            else
            {
                m_barRectangle.Width = (int)(m_progressPercentage * (m_rect.Width - (m_margins.Left + m_margins.Right)) / 100.0f);
                m_barRectangle.X = (int)(m_rect.X + m_margins.Left);
                m_barRectangle.Y = (int)(m_rect.Y + m_margins.Top);
                m_barRectangle.Height = (int)(m_rect.Height - m_margins.Top - m_margins.Bottom);
            }
            m_barTexture.Rectangle = m_barRectangle;
            m_subrect = m_barTexture.AnimationState.GetCurrentAnimationState();
            if (!m_stretchBar)
            {
                m_subrect.Y = 0;
                m_subrect.X = 0;
                if (Vertical)
                {
                    m_subrect.Width = m_barTexture.Body.Width;
                    m_subrect.Height = (int)Math.Ceiling(m_progressPercentage * m_barTexture.Body.Height / 100.0f);
                }
                else
                {
                    m_subrect.Height = m_barTexture.Body.Height;
                    m_subrect.Width = (int)Math.Ceiling(m_progressPercentage * m_barTexture.Body.Width / 100.0f);
                }
            }
            else
            {
                m_subrect.Y = 0;
                m_subrect.X = 0;
                if (Vertical)
                {
                    m_subrect.Height = m_barTexture.Body.Height;
                    m_subrect.Width = m_barTexture.Body.Width;
                }
                else
                {
                    m_subrect.Height = m_barTexture.Body.Height;
                    m_subrect.Width = m_barTexture.Body.Width;
                }
            }
        }

        public override bool Update(GameTime gameTime)
        {
            if (m_updated)
            {
                updateBarSize();
                m_updated = false;
            }
            return base.Update(gameTime);
        }

        public override bool Draw(GameTime gameTime)
        {
            if (Vertical && m_barRectangle.Height > 0)
            {
                m_barTexture.AnimationState.SetCurrentAnimationState(m_subrect);
                m_barTexture.Draw(gameTime);
            }
            else if (!Vertical && m_barRectangle.Width > 0)
            {
                m_barTexture.AnimationState.SetCurrentAnimationState(m_subrect);
                m_barTexture.Draw(gameTime);
            }

            base.Draw(gameTime);
            
            if (m_displayText && m_percentage != null)
                SpriteBatch.DrawString(m_spriteFont, m_percentage, m_stringPos, m_textColor);
            return true;
        }

        #endregion
    }
}
